<script lang="ts">
    import Icon from "../Common/Icons/Icon.svelte";
    import { useFormItemContext } from "../FormItem/FormItem.svelte";
    import { useClassList } from "../utils/useClassList";
    import { useStyle } from "../utils/useStyle";
    import { WordCount } from "../WordCount";
    import type { InputProps } from "./Input";

    let { value = $bindable(""), ...props }: InputProps = $props();
    const ctx = useFormItemContext();
    let valForCount = $state(value);
    let isCompositioning = $state(false);
    let type = $state(props.type || "text");
    const { name, style, disabled, size, append, prepend, prefix, suffix, suffixStyle, prefixStyle, clearable, onchange, onenter, onkeydown, onkeyup, oninput, password, ...others } = props;
    delete others["type"];

    const clazzName = $derived(
        useClassList(props, "cm-input-wrapper", {
            "cm-input-disabled": props.disabled,
            "cm-input-auto-height": props.autoHeight,
            "cm-textarea": type === "textarea",
            "cm-input-hidden": type === "hidden",
            [`cm-input-${props.size}`]: props.size,
            "cm-input-group-with-prefix": props.prefix,
            "cm-input-group-with-suffix": props.suffix || props.password,
            "cm-input-group-with-append": props.append,
            "cm-input-group-with-prepend": props.prepend,
        })
    );

    const inputStyle = $derived.by(() => {
        const styles: any = {};
        if (props.suffixStyle && props.suffixStyle.width) {
            styles["padding-right"] = props.suffixStyle.width + "px";
        }
        if (props.prefixStyle && props.prefixStyle.width) {
            styles["padding-left"] = props.prefixStyle.width + "px";
        }
        return useStyle({}, styles);
    });

    const togglePassword = () => {
        type = type === "password" ? "text" : "password";
    };
    const _onInput = (e: any) => {
        // 输入中文时，不触发change
        if (!isCompositioning) {
            value = e.target.value;
            if (props.onchange) {
                props.onchange(e.target.value);
            }
            ctx?.onFieldChange?.();
        }
        valForCount = e.target.value;
        props.oninput?.(e.target.value, e);
        type === "textarea" && props.autoHeight && _autoHeight(e);
    };

    const _onCompositionStart = (e: any) => {
        isCompositioning = true;
        props.oncompositionstart?.(e);
    };

    const _onCompositionEnd = (e: any) => {
        isCompositioning = false;
        _onInput(e);
        props.oncompositionend?.(e);
    };

    let initHeight: number;

    const _autoHeight = (event: any) => {
        const ele = event.target;
        if (!initHeight) {
            initHeight = ele.clientHeight;
        }
        if (ele.scrollHeight > initHeight) {
            if (ele.value.split("\n").length === 1) {
                ele.style.height = `${initHeight}px`;
            } else {
                ele.style.height = "auto";
            }
            ele.style.overflowY = "hidden";
            ele.scrollTop = 0; // 防抖动
            ele.style.height = `${ele.scrollHeight}px`;
        }
    };

    const onBlurChange = (e: any) => {
        // const v = e.target.value;
        // value = v;
        // if (trigger === "blur") {
        // props.onchange?.(v);
        ctx?.onFieldBlur?.();
        // }
        props.onblur?.(e);
    };

    const clear = () => {
        value = "";
        props.onchange?.("");
        ctx?.onFieldChange?.();
    };

    const _onKeyUp = (e: any) => {
        if (e.keyCode === 13) {
            props.onenter?.(value);
        }
        props.onkeyup?.(e);
    };

    const _onKeyDown = (e: any) => {
        if (e.keyCode === 13) {
            value = e.target.value;
            props.onchange?.(e.target.value);
        }
        props.onkeydown?.(e);
    };
</script>

{#snippet renderSuffix()}
    {#if props.password}
        {#if type === "password"}
            <Icon icon="eyeOff" class="cm-input-password-icon" onclick={togglePassword} />
        {:else}
            <Icon icon="eye" class="cm-input-password-icon" onclick={togglePassword} />
        {/if}
    {:else if props.suffix}
        {#if typeof props.suffix === "function"}
            {@render props.suffix()}
        {:else}
            {props.suffix}
        {/if}
    {/if}
{/snippet}
<div class={clazzName} style={props.style}>
    {#if props.prefix}
        <div class="cm-input-prefix" style={props.prefixStyle}>
            {#if typeof props.prefix === "function"}
                {@render props.prefix()}
            {:else}
                {props.prefix}
            {/if}
        </div>
    {/if}
    {#if props.prepend}
        <div class="cm-input-group-prepend">
            {#if typeof props.prepend === "function"}
                {@render props.prepend()}
            {:else}
                {props.prepend}
            {/if}
        </div>
    {/if}
    {#if type === "textarea"}
        <textarea
            {...others}
            class="cm-input"
            bind:value
            spellcheck={false}
            autocomplete={props.autocomplete || "off"}
            wrap="soft"
            oninput={_onInput}
            onblur={onBlurChange}
            disabled={props.disabled}
            style={inputStyle}
            onkeydown={_onKeyDown}
            onkeyup={_onKeyUp}
        ></textarea>
    {:else}
        <input
            {...others}
            class="cm-input"
            bind:value
            autocomplete={props.autocomplete || "off"}
            oninput={_onInput}
            onblur={onBlurChange}
            disabled={props.disabled}
            style={inputStyle}
            onkeydown={_onKeyDown}
            onkeyup={_onKeyUp}
            {type}
            oncompositionstart={_onCompositionStart}
            oncompositionend={_onCompositionEnd}
        />
    {/if}
    {#if props.clearable && value}
        <Icon icon="times" class="cm-input-clear" onclick={clear} size={14} />
    {/if}
    {#if props.suffix || props.password || (props.wordCount && props.maxLength)}
        <div class="cm-input-suffix" style={props.suffixStyle}>
            {#if props.wordCount && props.maxLength}
                <WordCount total={props.maxLength!} value={valForCount} />
            {:else}
                {@render renderSuffix()}
            {/if}
        </div>
    {/if}
    {#if props.append}
        <div class={`cm-input-group-append`}>
            {#if typeof props.append === "function"}
                {@render props.append()}
            {:else}
                {props.append}
            {/if}
        </div>
    {/if}
</div>
